import { Autoplainning } from "Autoplanning/Autoplainning";
import { APollingTask, CacheData } from "../../PollingStation";
import { AutoPlanManager } from "Autoplanning/AutoPlanManager";
import { ZipRoomPlan } from "utils/plan/ZipRoomPlan";
import { AllEntityTypes, EntityType } from "GameLoop/WorldState/EntityManager/Entitys/Entity.interface";
import { RampartSample } from "algorithm/Cluster/Sample/RampartSample";
import { DBScan } from "algorithm/Cluster/DBScan";
import { PositionHelper } from "utils/position/PositionHelper";
import { dangrous_style } from "utils/constants/globalconstant";
import { Math2D } from "algorithm/Math2d";
// const moduleTypemap:Record<string,EntityType>={
//     source:"SpawnEntity",
//     minerial:"SpawnEntity",
//     controller:"SpawnEntity",
//     spawn:"SpawnEntity",
//     labs:"SpawnEntity",
//     core:"SpawnEntity",
//     room:"SpawnEntity",
//     rampart:"SpawnEntity",
// }
const moduleTypeMap:Record<EntityType,string>={
    InnerMineEntity:"source",
    SpawnEntity:"spawn",
    MinerialEntity:"minerial",
    // source:"controller",
    LabEntity:"labs",
    CoreEntity:"core",
    // source:"room",
    // source:"rampart",
     
} as any

export class CacheBlueplan<T extends ICacheData=ICacheData> extends CacheData<T>
{
    code!:string;
    plans:Record<string,IPlanStrategy>={};
    plancost!:CostMatrix;   // 普通布局的建筑蓝图矩阵
    safe_matrix_drawing!:string;
    private safe_region!:IFVector2[];// 城墙包围的安全区域
    private safe_matrix!:CostMatrix;
    private group_rampart!:Record<number,IFVector2[]>;    // 分段的城墙,key 1D的坐标
    public init()
    {
        const coreplan=  this.getModulePlan("CoreEntity")[0];
        const rampartplan=  this.getModulePlan("rampart" as any)[0].structures[STRUCTURE_RAMPART];
        const core={x: coreplan.pos.x,y: coreplan.pos.y+2};
        this.safe_region = Autoplainning.FindSafeRegion(this.code,rampartplan ,core);
            // Memory.Debug[`rampart positions ${this.roomName}`]=this.RampartPositions;
        const init_arr = Array<number>(625).fill(0xffffffff);
        this.safe_matrix =  PathFinder.CostMatrix.deserialize(init_arr);
        for(const item of this.safe_region)
        {
            // init_arr[item.x+item.y*50]=0;
            this.safe_matrix.set(item.x,item.y,1);
            
        }
        const setRingMask = (core:IFVector2,range:number,val:number)=>
        {
            const pos1 = _.flatten(PositionHelper.findRingOfPosition(PositionHelper.Create({roomName:this.code,x:core.x,y:core.y}),range));
            for(const p of pos1)
            {
                if(this.safe_matrix.get(p.x,p.y)<val)
                {
                    this.safe_matrix.set(p.x,p.y,val);
                }
            }
        }
        for(const item of rampartplan)
        {
            setRingMask(item,1,0x44);
            setRingMask(item,2,0x22);
            // setRingMask(item,3,0x11);
          
        }
       
        // 3.城墙分段
        const groupRampart = this.classifyRampart(rampartplan);

        this.group_rampart={};

        for(const g of groupRampart)
        {

            const avg = this.avg(g);
            this.group_rampart[avg.x+avg.y*50] = g;

            // 补充额外的ram
            {
                const addtionRam = this.supplementRampart(Game.rooms[this.code],g,this.safe_matrix);
                // Memory.Debug[`${this.code}_${avg.x}_${avg.y}`]= addtionRam;
                rampartplan.push(...addtionRam);
            }
            
        }
        {
            // ram 设置为 1
            rampartplan.forEach(e=>
                {
                    this.safe_matrix.set(e.x,e.y,1);
                })
        }
       
        for(let x=0;x<50;x++)
        {
            for (let y=0;y<50;y++)
            {
                if(this.safe_matrix.get(x,y) >0x88)
                {
                    dangrous_style
                    Game.rooms[this.code].visual.text(`${this.safe_matrix.get(x,y).toString(16)}`,x,y,{color:'#fa0000',font:0.3});
                }
                else if(this.safe_matrix.get(x,y) >0x22)
                {
                    Game.rooms[this.code].visual.text(`${this.safe_matrix.get(x,y).toString(16)}`,x,y,{color:'#da0000',font:0.3});
                }
                else if(this.safe_matrix.get(x,y) >0x11)
                {
                    Game.rooms[this.code].visual.text(`${this.safe_matrix.get(x,y).toString(16)}`,x,y,{color:'#dad1000',font:0.3});
                }
                else if(this.safe_matrix.get(x,y) >0x4)
                {
                    Game.rooms[this.code].visual.text(`${this.safe_matrix.get(x,y).toString(16)}`,x,y,{color:'#00d100',font:0.3});
                }
                else 
                {
                    Game.rooms[this.code].visual.text(`${this.safe_matrix.get(x,y).toString(16)}`,x,y,{color:'#00f100',font:0.3});
                }
            }
        }
        this.safe_matrix_drawing =  Game.rooms[this.code].visual.export();
        
    }
    /**
     * 补充小段ram,从两端补充
     * @param thisrams 当前需要补充的ram段
     * @param thisrams 参考ram
     * 
     */
    private supplementRampart(room:Room,thisrams:IFVector2[],matrix:CostMatrix)
    {
       
        const getEndPoint = (ps:IFVector2[])=>
        {
            if(ps.length ==1)
            {
                return ps;
            }
            return ps.filter(e=> ps.filter(p=>Math2D.distancetosqrt(e,p) == 1 ).length ==1 )
        }
        
        let s_p =  getEndPoint(thisrams) ;
       
        const getextendRams = (room:Room,curpos:IFVector2,rams:IFVector2[])=>
        {
            let first_space = 0xff;
            const addram:IFVector2[]=[];
            let next = curpos;
            while(next&&  first_space!= 1 && addram.length<3)
            {
                const nextposs = PositionHelper.getFreeSpace({roomName:room.name,x:next.x,y:next.y},1) .filter(p=> 
                    {
                        if(matrix.get(p.x,p.y)>=first_space)
                        {
                            return false;
                        }
                        const freepos = PositionHelper.getFreeSpace({roomName:room.name,x:p.x,y:p.y },1 );
                        if(freepos.length<4)
                        {
                            return false;
                        }
                        if(rams.find(r=>Math2D.distanceto(r,p)==0))
                        {
                            // 在ram组里的
                            return false;
                        }
                        return true;
                    } ) ;
                if(nextposs.length==0)
                {
                    break;
                }
                const minp = _.min(nextposs,p=>matrix.get(p.x,p.y)+PositionHelper.getFreeSpace({roomName:room.name,x:p.x,y:p.y },1 ).length);
              
                if(minp)
                {
                   
                    first_space = matrix.get(minp.x,minp.y);
                    //Memory.Debug[`${this.code}_${next.x}_${next.y}_${minp.x}_${minp.y}`]= `计算新增ram[${first_space}]`+JSON.stringify(addram)+`poss:${JSON.stringify(nextposs)}`;
                    if(first_space == 1)
                    {
                        break;
                    }
                    addram.push({x:minp.x,y:minp.y}); 
                    next = {x:minp.x,y:minp.y};
                }
                else 
                {
                    break;
                }
            }
            return addram
        }
        const addrams:IFVector2[]=[];
        // if(s_p.length>0)
        // {
        //     Memory.Debug[`${this.code}_${s_p[0].x}_${s_p[0].y}_端点`]= `端点[${JSON.stringify(s_p)}]`;
        // }
        
        for(const e of s_p)
        {
            const ram = getextendRams(room,e,thisrams);
           
            addrams.push(...ram);
        }
        return addrams;
    }

    public getNormalPlan()
    {
        if(this.plans["normal"])
        {
            return this.plans["normal"]
        }
        const roomplanstring =  Autoplainning.InquireRoomplan(this.code);
        if(!roomplanstring)
        {
            throw  new Error(`ERROR:找不到房间${this.code}的建筑计划`);
        }
        const roomplan = ZipRoomPlan.Unzip(roomplanstring);
        this.plans["normal"] = AutoPlanManager.AddRoomPlan(this.code,roomplan);
        return this.plans["normal"]
    }
    public getModulePlan(type:EntityType)
    {
        const realType = moduleTypeMap[type]?moduleTypeMap[type]:type;
        return this.getNormalPlan().ModulePlan.filter(e=>e.type .startsWith(realType));
    }

    public getMatrix()
    {
        if(this.plancost)
        {
            return this.plancost.clone();
        }
        const planstrategy = this.getNormalPlan();
        const matrix = new PathFinder.CostMatrix();
        for(const e of planstrategy.SiteQueue.items)
        {
            if(e.type == STRUCTURE_CONTAINER || e.type ==STRUCTURE_RAMPART || e.type ==STRUCTURE_ROAD)
            {
                continue;
            }
            matrix.set(e.pos.x,e.pos.y,0xff);
        }
        this.plancost = matrix;
        return this.plancost
    }

    public getSafeMatrix()
    {
        return this.safe_matrix;
    }
    /**
     * 判断是否在防守的ram之内
     * @param pos 
     * @returns 
     */
    public isInDefendRampart(pos:RoomPosition):boolean
    {
        const getDistance = (p1:IFVector2,p2:IFVector2)=>
        {
            const dis_x = Math.abs(p1.x -p2.x);
            const dis_y = Math.abs(p1.y -p2.y);
            return Math.max(dis_x,dis_y);
        }
        if(this.group_rampart)
        {
            const nearkey = _.min(Object.keys(this.group_rampart),e=> {
                let key = parseInt(e);
                return getDistance({x:key%50,y:Math.floor(key/50)},pos);
            });
            const poss = this.group_rampart[parseInt(nearkey)];
            if(!poss)
            {
                return false;
            }
            for(const e of poss)
            {
                if(pos.x == e.x && pos.y==e.y)
                {
                    return true;
                }
            }
        }
        return false;
    }
    public isInSafeRagion(pos:IRoomPosition)
    {
        if(this.getSafeMatrix().get(pos.x,pos.y)== 0)
        {
            return true;
        }
        return false;
    }
     /*
    * 查找防御位置
    */
    public findDefendPosition(pos:RoomPosition,isingoreCreep:boolean=true):RoomPosition|undefined
    {
        if(this.group_rampart)
        {
            // 1.查找到最近的rampart位置
            const sortkeys = _.sortBy(Object.keys(this.group_rampart),e=>
            {
                let key = parseInt(e);
                const target = {x:key%50,y:Math.floor(key/50)};
                return PositionHelper.getDistance(target,pos);
            })
            for(let k of sortkeys)
            {
                const nearpos = this.findOneDefendPostion(this.group_rampart[parseInt(k)],pos,isingoreCreep);
                if(nearpos)
                {
                    return PositionHelper.Create({x:nearpos.x,y:nearpos.y,roomName:pos.roomName})
                }
            }
        }
        return undefined;
    }
 
     /**
      * 
      * @param pos 备选位置
      * @param isingoreCreep true:排除掉已经被爬站了位置
      */
    private findOneDefendPostion(defpos:IFVector2[],pos:RoomPosition,isingoreCreep:boolean=true)
    {  
        const nearestram = _.min(defpos,e=>
        {
            const distance_ =  PositionHelper.getDistance(pos,e);
            if(isingoreCreep &&PositionHelper.lookFor(LOOK_CREEPS,{x:e.x,y:e.y,roomName:pos.roomName}).length>0)
            {
                return distance_+50;
            }
            return distance_
        });
        const dis =   PositionHelper.getDistance(pos,nearestram);
        if(dis>49)
        {
            return undefined;
        }
        return nearestram;
    }
    private  classifyRampart(rampart_pos:IFVector2[])
    {
        const samples = _.map(rampart_pos,e=>new RampartSample<IFVector2>(e));
        const groups = DBScan.classify<RampartSample<IFVector2>>(samples,1,1);

        const armys=_.map(groups.cluster,e=>_.map(Array.from(e),i=>i.Data));
        armys.push(..._.map(groups.left,e=>[e.Data]));
        return armys;
    }
    private avg<T extends IFVector2=IFVector2>(arr:IFVector2[])
    {
        const x = Math.round(_.sum(arr,e=>e.x)/arr.length);
        const y = Math.round(_.sum(arr,e=>e.y)/arr.length);
        return {x:x,y:y}
    }
}

export class CacheBlueplanTask<T extends CacheBlueplan<ICacheData> = CacheBlueplan<ICacheData>> extends APollingTask<T>
{
    // roomName!:string;

    Update(...arg:any[]): void
    {
        // this.roomName = arg[0];
        console.log(`获取蓝图 ${this.code}`);
        const room = Game.rooms[this.code];
        if(room)
        {
            if(Autoplainning.createPlan(this.code))
            {
                this.value = new CacheBlueplan<ICacheSourceTask>([]) as unknown as  T;
                this.value.code = this.code;
                this.value.init();
              
                this.lastupdate =-1;
            }
            else
            {
                throw new Error(`创建或查询布局失败:${this.code}`);
            }
        }
    }

}
